package com.hue.spring;

import com.hue.spring.annotation.Component;
import com.hue.spring.annotation.ComponentScan;
import com.hue.spring.annotation.Scope;

import java.io.File;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/*
    Spring容器类
 */
public class ApplicationContext {
    //配置类
    private Class configClass;

    //单例池，spring的ioc容器
    private ConcurrentHashMap<String, Object> singleMaps = new ConcurrentHashMap<>();

    //bean的定义集合,加载一个bean后，就将bean的定义加入进来
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();


    public ApplicationContext(Class configClass) throws Exception {
        this.configClass = configClass;
        //解析配置类,获取所有的beanDefinition
        scan(configClass);
        //将所有的单例bean生成对象，加入到容器中
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (beanDefinition.getScope().equals("single")) { //创建bean
                Object bean = createBean(beanDefinition);
                //将beam加入到容器中
                singleMaps.put(beanName, bean);
            }
        }
    }

    //获取对象的方法
    public Object getBean(String beanName) {
        if (beanDefinitionMap.containsKey(beanName)) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("single")) { //是单例,从单例池中获取返回
                return singleMaps.get(beanName);
            } else {
                return createBean(beanDefinition);
            }
        } else {
            throw new RuntimeException(beanName + "不存在!");
        }
    }

    /*
        扫描配置类上Component注解，生成所有的beanDefinition，并且加入到beanDefinitionMap中
     */
    public void scan(Class configClass) throws Exception {
        //获取配置上的ComponentScan注解
        ComponentScan componentAnno = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        if (componentAnno != null) {    //当有这个注解时才执行
            //获取注解上的包扫描路径
            String path = componentAnno.value();
            path = path.replace(".", "/");
            //扫描path下的所有类，将有Component注解的类生成单例对象加入到ioc容器
            //得到应用程序类加载器
            ClassLoader classLoader = ApplicationContext.class.getClassLoader();
            //使用类加载器得到目录的绝对路径
            URL url = classLoader.getResource(path);
            //将url解码
            URL url1 = new URL(URLDecoder.decode(url.toString(), "UTF-8"));
            //得到文件句柄
            File file = new File(url1.getFile());
            if (file.isDirectory()) { //如果是一个文件夹
                //获取文件夹下的所有文件
                File[] files = file.listFiles();
                for (File f : files) {
                    //如果文件是以.class结尾,就加载这个类
                    if (f.getPath().endsWith(".class")) {
                        //将绝对路径转换为类的全限定类名,然后使用类加载器加载这个类
                        String classPath = f.getAbsolutePath();
                        classPath = classPath.substring(classPath.indexOf("com"), classPath.indexOf(".class"));
                        classPath = classPath.replace("\\", ".");
                        //加载类
                        Class<?> aClass = Class.forName(classPath);
                        //如果有@Component注解
                        if (aClass.isAnnotationPresent(Component.class)) {
                            //获取bean的名字
                            Component component = aClass.getAnnotation(Component.class);
                            String beanName = component.value();
                            //创建这个bean的定义
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setaClass(aClass);
                            if (aClass.isAnnotationPresent(Scope.class)) {    //有scope注解
                                //获取对象的Scope注解
                                Scope scope = aClass.getAnnotation(Scope.class);
                                //获取作用域
                                String value = scope.value();
                                if (value.equals("single")) { //单例,创建对象，加入到容器
                                    beanDefinition.setScope("single");
                                } else if (value.equals("prototype")) {    //原型
                                    beanDefinition.setScope("prototype");
                                }
                            } else { //没有scope就为单例,创建对象加入到容器
                                beanDefinition.setScope("single");
                            }
                            //将beanDefinition加入到beanDefinitionMap中
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    }
                }
            }
        }
    }

    /*
        根据beanDefinition创建一个bean的实例
     */
    public Object createBean(BeanDefinition beanDefinition) {
        Class aClass = beanDefinition.getaClass();
        Object o = null;
        try {
            o = aClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return o;
    }
}
